﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;

namespace SerialTool
{
    public partial class FormMain : Form
    {

        delegate void ShowFrameHandler(Frame frame);

        SerialPort serialPort = new SerialPort();
        FrameManager frameManager;
        byte[] txBuffer = new byte[2048];
        byte[] txData=new byte[2048];

        int txLength = 0;

        public FormMain()
        {
            InitializeComponent();

            frameManager = new FrameManager(serialPort);

            frameManager.AddFilter(new FrameFilter(this));

        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            toolStripComboBox1.DropDownStyle = ComboBoxStyle.DropDownList;
            string[] ports = SerialPort.GetPortNames();
            if (ports != null)
            {
                for (int i = 0; i < ports.Length; i++)
                {
                    toolStripComboBox1.Items.Add(ports[i]);
                }
            }
            if (toolStripComboBox1.Items.Count > 0)
            {
                toolStripComboBox1.SelectedIndex = 0;
            }

            groupBox1.Enabled = false;
        }

        private void buttonStart_Click(object sender, EventArgs e)
        {
            if (serialPort.IsOpen)
            {
                try
                {
                    serialPort.Close();
                    buttonStart.Text = "打开";
                    toolStripComboBox1.Enabled = true;
                    buttonStart.Image = Properties.Resources.Play;
                    groupBox1.Enabled = false;
                }
                catch { }
            }
            else
            {
                try
                {
                    serialPort.PortName = toolStripComboBox1.Text;
                    serialPort.BaudRate = 115200;
                    serialPort.Open();
                    buttonStart.Text = "关闭";
                    toolStripComboBox1.Enabled = false;
                    buttonStart.Image = Properties.Resources.Stop;
                    groupBox1.Enabled = true;
                }
                catch(Exception ex) {
                    MessageBox.Show(ex.Message);
                }
            }
        }

        private void buttonClear_Click(object sender, EventArgs e)
        {
            textBoxRx.Clear();
        }



        void TransmiteFrame(byte[] data, int length)
        {

            if (length <= 0) return;
            int dataLen = length + 2;


            //计算CRC
            txBuffer[0] = (byte)((dataLen >> 8) & 0xff);
            txBuffer[1] = (byte)(dataLen & 0xff);

            for (int i = 0; i < length; i++)
            {
                txBuffer[i + 2] = data[i];
            }

            UInt16 crc = CRC16.ComputeCRC16(txBuffer, 0, dataLen);

            int index = 0;

            //帧头
            txBuffer[index] = 0x10;
            index++;
            txBuffer[index] = 0x02;
            index++;


            //数据长度
            txBuffer[index] = (byte)((dataLen >> 8) & 0xff);
            index++;
            if (txBuffer[index - 1] == 0x10)
            {
                txBuffer[index] = 0x10;
                index++;
            }
            txBuffer[index] = (byte)(dataLen & 0xff);
            index++;
            if (txBuffer[index - 1] == 0x10)
            {
                txBuffer[index] = 0x10;
                index++;
            }
            //数据
            for (int i = 0; i < length; i++)
            {
                txBuffer[index] = data[i];
                index++;
                if (txBuffer[index - 1] == 0x10)
                {
                    txBuffer[index] = 0x10;
                    index++;
                }
            }
            //CRC
            txBuffer[index] = (byte)((crc >> 8) & 0xff);
            index++;
            if (txBuffer[index - 1] == 0x10)
            {
                txBuffer[index] = 0x10;
                index++;
            }
            txBuffer[index] = (byte)(crc & 0xff);
            index++;
            if (txBuffer[index - 1] == 0x10)
            {
                txBuffer[index] = 0x10;
                index++;
            }
            //帧尾
            txBuffer[index] = 0x10;
            index++;
            txBuffer[index] = 0x03;
            index++;


            

            if (serialPort.IsOpen)
            {
                try
                {
                    //发送数据
                    serialPort.Write(txBuffer, 0, index);
                }
                catch (Exception) { }
            }
        }

        private void buttonSend_Click(object sender, EventArgs e)
        {
            PrepareData();
            
            TransmiteFrame(txData, txLength);
        }


        private void PrepareData()
        {
            txData[0] = byte.Parse(textBox2.Text, System.Globalization.NumberStyles.AllowHexSpecifier); //源端口 (测试仪)
            txData[1] = 0;//源地址长度
            txData[2] = byte.Parse(textBox3.Text, System.Globalization.NumberStyles.AllowHexSpecifier) ; //目的端口号 (记录板)
            txData[3] = 0; //目的地址长度

            txData[4] = byte.Parse(textBox4.Text, System.Globalization.NumberStyles.AllowHexSpecifier) ;//业务类型
            txData[5] = byte.Parse(textBox5.Text, System.Globalization.NumberStyles.AllowHexSpecifier);//命令


            string[] dataStr = textBox6.Text.Split(new char[] {' ','\t','\r','\n' }, StringSplitOptions.RemoveEmptyEntries);

            for (int i = 0; i < dataStr.Length; i++)
            {
                txData[6 + i] = byte.Parse(dataStr[i], System.Globalization.NumberStyles.AllowHexSpecifier);
            }

            txLength = 6 + dataStr.Length;
        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBox1.Checked)
            {
                PrepareData();
                needSendCount = int.Parse(textBox7.Text);
                timer1.Interval = int.Parse(textBox1.Text);
                timer1.Enabled = true;
                buttonSend.Enabled = false;
            }
            else
            {
                timer1.Enabled = false;
                buttonSend.Enabled = true;
            }
        }

        int needSendCount = 0;

        private void timer1_Tick(object sender, EventArgs e)
        {
            if (needSendCount <= 0)
            {
                timer1.Enabled = false;
                buttonSend.Enabled = true;
                checkBox1.Checked = false;
            }
            else
            {
                TransmiteFrame(txData, txLength);
                needSendCount--;
            }
            
        }


        public void ShowFrame(Frame frame)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new ShowFrameHandler(ShowFrame),new object[]{frame});
            }
            else
            {
                textBoxRx.AppendText(frame.ToString());
                textBoxRx.AppendText("\r\n");
            }
        }


        class FrameFilter : IFrameFilter
        {


            FormMain form;

            public FrameFilter(FormMain form)
            {
                this.form = form;
            }

            #region IFrameFilter 成员

            public bool Match(Frame frame)
            {
                return true;
            }

            public void AddFrame(Frame frame)
            {
                this.form.ShowFrame(frame);
            }

            public Frame GetFrame(int timeout)
            {
                return null;
            }

            #endregion
        }


        class ValCalFilter : IFrameFilter
        {

            FormValCal form;
            public ValCalFilter(FormValCal form)
            {
                this.form = form;
            }

            #region IFrameFilter 成员

            public bool Match(Frame frame)
            {
                return true;
            }

            public void AddFrame(Frame frame)
            {
                if (this.form != null &&(this.form.IsDisposed==false))
                {
                    form.CalFrame(frame);
                }
            }

            public Frame GetFrame(int timeout)
            {
                return null;
            }

            #endregion
        }

        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            FormValCal formVal = new FormValCal();
            formVal.Owner = this;
            formVal.Show();
            frameManager.AddFilter(new ValCalFilter(formVal));
        }
    }
}
